﻿namespace DeploymentCustomActions
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.IO;
    using System.IO.Packaging;
    using Microsoft.Deployment.WindowsInstaller;

    public sealed class Utility
    {
        private Utility() { }

        #region ZIP
        public const string MZipExtension = ".mzip";

        public static void Unzip(string sourcePath, string baseFolder)
        {
            if (Directory.Exists(baseFolder)) Directory.Delete(baseFolder, true);
            Directory.CreateDirectory(baseFolder);

            using (FileStream sourceStream = new FileStream(sourcePath, FileMode.Open))
            {
                using (Package package = Package.Open(sourceStream, FileMode.Open))
                {
                    foreach (PackagePart zipPart in package.GetParts())
                    {
                        string path = Path.Combine(baseFolder, zipPart.Uri.ToString().Substring(1));

                        using (Stream zipStream = zipPart.GetStream())
                        {
                            using (FileStream fileStream = new FileStream(path, FileMode.Create))
                            {
                                zipStream.CopyTo(fileStream);
                            }
                        }

                        if (GetFileExtentionName(path) == MZipExtension)
                        {
                            Unzip(path, TrimMZipExtension(path));
                            File.Delete(path);
                        }
                    }
                }
            }
        }

        public static void Zip(string folderPath)
        {
            IEnumerable<string> subDirectories = Directory.EnumerateDirectories(folderPath, "*", SearchOption.TopDirectoryOnly);
            foreach (var directory in subDirectories)
            {
                Zip(directory);
            }
            ZipFilesInDirectory(folderPath);
        }

        private static void ZipFilesInDirectory(string folderPath)
        {
            var files = Directory.EnumerateFiles(folderPath, "*", SearchOption.TopDirectoryOnly);
            using (FileStream destination = new FileStream(AppendMZipExtension(folderPath), FileMode.Create))
            {
                using (Package package = Package.Open(destination, FileMode.Create))
                {
                    foreach (string path in files)
                    {
                        Uri fileUri = new Uri(@"/" + Path.GetFileName(path), UriKind.Relative);
                        string contentType = @"data/" + GetFileExtentionName(path);

                        using (Stream zipStream = package.CreatePart(fileUri, contentType, CompressionOption.Fast).GetStream())
                        {
                            using (FileStream fileStream = new FileStream(path, FileMode.Open))
                            {
                                fileStream.CopyTo(zipStream);
                            }
                        }
                    }
                }
            }
        }

        private static string GetFileExtentionName(string path)
        {
            string extention = Path.GetExtension(path);
            return extention;
        }

        private static string TrimMZipExtension(string path)
        {
            return path.Replace(MZipExtension, "");
        }

        private static string AppendMZipExtension(string folderPath)
        {
            return folderPath.TrimEnd('\\') + MZipExtension;
        }

        #endregion 

        #region Session Database
        public static void ExtractContentFromBinaryTable(Session session, string binaryKeyName, string outputFile)
        {
            if (session == null) return;

            using (var db = session.Database)
            {
                using (var view = db.OpenView("SELECT `Data` FROM `Binary` WHERE `Name` = '{0}'", binaryKeyName))
                {
                    view.Execute();
                    Record rec = view.Fetch();

                    Stream inStream = rec.GetStream("Data");
                    if (inStream != null)
                    {
                        using (FileStream file = File.OpenWrite(outputFile))
                        {
                            CopyStream(inStream, file);
                        }
                        
                    }
                }
            }
        }

        private static void CopyStream(Stream input, Stream output)
        {
            byte[] buffer = new byte[8 * 1024];
            int len;
            while ((len = input.Read(buffer, 0, buffer.Length)) > 0)
            {
                output.Write(buffer, 0, len);
            }
        }
        #endregion
    }
}
